import argparse
import backtrader as bt
from datetime import datetime as dt
from time import time
from multiprocessing import cpu_count, Process
import os

from os.path import join, exists, dirname
if __name__ == '__main__':
    import sys
    sys.path.append(dirname(dirname(__file__)))
from strategies.netEasySevenStar import SevenStar
from utils.localdata import onebyone, download

ps = dict(
        version = ('Y', 'Z'),     # 'Y': 阴阳版、'Z':涨跌版
        risestop1 = [1+x/100 for x in range(3, 21, 2)],   # 高位回落10%止盈
        risestop2 = [1+x/100 for x in range(5, 50, 3)],  # 计划止盈
        fallstop = [x/100 for x in range(70,99,5)],   # 止损
        afterdown = [False, True],  # 是否检测下降通道
)

ps2 = dict(
        maperiod = [22, 60],     # 均线判断下降
        hiperiod = [80, 100, 150],    # 下降检测的高点范围
        downrate = [50, 65, 80],    # 均线低于高点的70% 即下降了 30%
)
ps2 = None

def pps(p={}, ks=list(ps.keys()), ps=ps, ps2=ps2):
    if len(ks) > 0:
        for x in ps[ks[0]]:
            yield from pps(dict({f'{ks[0]}': x}, **p), ks[1:], ps, ps2)
    elif p['afterdown'] and ps2:
        yield from pps(p, list(ps2.keys()), ps2, None)
    else:
        yield p

def main(num, pss, StrategyClass=SevenStar):
    logfile = join('logs', f's{num:03d}_{dt.now().isoformat()}_{os.getpid()}.log')
    def log(text, write=False, file=logfile, cache=dict(a=[])):
        lines = cache['a']
        lines.append(f'{dt.now().isoformat()} {text}')
        if write:
            with open(file, 'a', encoding='utf8') as f:
                f.write('\n'.join(lines))
            cache['a'] = ['\n']

    for p in pss:
        params = dict(dict(log=False), **p)
        total = 0
        # for daily_data, code, name in [d for d in onebyone(klen=300) if d[1] in ['sh.600378', 'sh.603333']]:
        for daily_data, code, name in onebyone(klen=300):
            params['code'] = code
            params['name'] = name
            cerebro = bt.Cerebro()
            # 设置启动资金
            cerebro.broker.setcash(10000000.0)
            # 设置佣金
            cerebro.broker.setcommission(commission=0.001)
            cerebro.addstrategy(StrategyClass, **params)
            data = bt.feeds.PandasData(dataname=daily_data)
            cerebro.adddata(data)
            cerebro.addsizer(bt.sizers.FixedSize, stake=100)  # 每笔交易使用固定交易量，stake代表交易量
            result = cerebro.run(plot=False)
            shouyi = cerebro.broker.getvalue() - 10000000
            total += shouyi
            log( f'{code} {name} 收益: {shouyi:.2f}')
        log(f'={total:.2f}={p}={dt.now()}'.replace('00000000000001', ''), True)

def parse_args():
    parser = argparse.ArgumentParser(
        description='七星落长空策略参数搜索-多进程')

    parser.add_argument('-n', default=cpu_count()-1, required=False, type=int, help='进程数')

    return parser.parse_args()

if __name__ == '__main__':
    args = parse_args()

    download()

    params = [x for x in pps()]
    size = (len(params) // (args.n - 1)) if args.n > 1 else len(params)

    for i in range(args.n):
        Process(target=main,kwargs={"num": i, "pss": params[size * i:size * (i + 1)]}).start()

    print(dt.now().isoformat(), f"主进程ID: {os.getpid()} 进程数量：{args.n} 参数组数量: {len(params)} 每个进程搜索参数组数量：{size}")
